#include "msp_uart.h"
//
#include <string.h>
// stm32 ll库
#include "stm32f1xx.h"
#include "stm32f1xx_ll_dma.h"
#include "stm32f1xx_ll_usart.h"
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_rcc.h"
#include "stm32f1xx_ll_gpio.h"
// lib
#include "debug.h"

#define MSP_UART_SUCCESS                    0
#define MSP_UART_FAILURE                    1

#if UART2_USE_DMA
static uint16_t uart2_rx_data_len  = 0;     // 读缓冲区内数据量
// static uint16_t uart2_tx_data_len  = 0;     // 写缓冲区内数据量
static uint8_t  uart2_rx_busy_flag = 0;     // 读缓冲区忙碌标志位
static uint8_t  uart2_tx_busy_flag = 0;     // 写缓冲区忙碌标志位
#endif

// uart收发缓冲区
#if UART2_USE_DMA
static uint8_t uart2_rx_buffer[UART2_RX_BUFFER_SIZE];
static uint8_t uart2_tx_buffer[UART2_TX_BUFFER_SIZE];
#endif

#if UART2_USE_DMA
static void Msp_Uart2_Write_Dma(uint16_t len);
static void MSP_Uart2_Read_Dma(uint16_t len);
#endif

#if 1 // MDK时使用
#pragma import(__use_no_semihosting)

// 标准库需要的支持函数
struct __FILE
{
    int handle;
};
FILE __stdout;

// 定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
    x = x;
}

// 重定义fputc函数
int fputc(int ch, FILE *f)
{
    while (!LL_USART_IsActiveFlag_TXE(USART2));         // 等待发送寄存器为空
    LL_USART_TransmitData8(USART2, ch);                 // 将数据写入发送寄存器
    return ch;
}
#endif

#if 0 // 仅在makefile时使用
/**
 * @brief 系统打印重映射到串口
 *
 * @param fd
 * @param ch
 * @param len
 * @return int
 */
int _write(int fd, char *ch, int len)
{
    for (uint16_t i = 0; i < len; i++)
    {
        while (!LL_USART_IsActiveFlag_TXE(USART2));     // 等待发送寄存器为空
        LL_USART_TransmitData8(USART2, ch[i]);          // 将数据写入发送寄存器
    }
    while (!LL_USART_IsActiveFlag_TC(USART2));          // 等待数据发送完成
    return len;
}
#endif

/**
 * @brief
 *
 * @param data
 * @param size
 */
void USART2_SendData(const uint8_t *data, uint16_t size)
{
    for (uint16_t i = 0; i < size; i++) {
        while (!LL_USART_IsActiveFlag_TXE(USART2));     // 等待发送寄存器为空
        LL_USART_TransmitData8(USART2, data[i]);        // 将数据写入发送寄存器
    }
    while (!LL_USART_IsActiveFlag_TC(USART2));          // 等待数据发送完成
}

#if 0
/**
 * @brief
 *
 * @param baud_rate
 */
void MSP_Usart1_Init(uint32_t baud_rate)
{
    LL_USART_InitTypeDef USART_InitStruct = {0};
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

    LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK1);

    /* Peripheral clock enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
    /**USART1 GPIO Configuration
    PA12 [PA10]   ------> USART1_DE
    PB6   ------> USART1_TX
    PB7   ------> USART1_RX
    */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* USART1 DMA Init */

    /* USART1_RX Init */
    LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_USART1_RX);
    LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
    LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
    LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
    LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
    LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
    LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
    LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);

    /* USART1_TX Init */
    LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_TX);
    LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
    LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
    LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
    LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
    LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
    LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
    LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);

    /* USART1 interrupt Init */
    NVIC_SetPriority(USART1_IRQn, 3);
    NVIC_EnableIRQ(USART1_IRQn);

    /* USART1 Init */
    USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
    USART_InitStruct.BaudRate = baud_rate;
    USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
    USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
    USART_InitStruct.Parity = LL_USART_PARITY_NONE;
    USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
    LL_USART_Init(USART1, &USART_InitStruct);
    LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
    LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
    LL_USART_EnableDEMode(USART1);
    LL_USART_SetDESignalPolarity(USART1, LL_USART_DE_POLARITY_HIGH);
    LL_USART_SetDEAssertionTime(USART1, 0);
    LL_USART_SetDEDeassertionTime(USART1, 0);
    LL_USART_DisableFIFO(USART1);
    LL_USART_ConfigAsyncMode(USART1);

    LL_USART_Enable(USART1);

    /* Polling USART1 initialisation */
    while ((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1))))
    {
    }
}
#endif

#if UART2_USE_DMA
/**
 * @brief 初始化串口2，使用DMA
 * 
 * @param baud_rate 
 */
void MSP_Usart2_Init(uint32_t baud_rate)
{
    LL_USART_InitTypeDef USART_InitStruct = {0};
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    //外设时钟---------------------------------------------------------------
    LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_PCLK1);
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
    //设置gpio---------------------------------------------------------------
    // PA2   ------> USART2_TX
    // PA3   ------> USART2_RX
    GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // 使能DMA中断
    NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3);
    NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
    NVIC_SetPriority(DMA1_Ch4_7_DMAMUX1_OVR_IRQn, 3);
    NVIC_EnableIRQ(DMA1_Ch4_7_DMAMUX1_OVR_IRQn);
    //设置接收DMA-------------------------------------------------------------
    LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMAMUX_REQ_USART2_RX);                               // 设置DMA1通道3的外设请求源为USART2的接收请求
    LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);             // 设置DMA1通道3的数据传输方向为从外设到内存
    LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_MEDIUM);                         // 设置DMA1通道3的优先级为中
    LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);                                             // 设置DMA1通道3的模式为正常模式
    LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);                             // 设置DMA1通道3的外设地址不增量
    LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);                               // 设置DMA1通道3的内存地址增量模式
    LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);                                   // 设置DMA1通道3的外设数据宽度为8位
    LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);                                   // 设置DMA1通道3的内存数据宽度为8位
    //设置发送DMA-------------------------------------------------------------
    LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMAMUX_REQ_USART2_TX);
    LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
    LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_MEDIUM);
    LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
    LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
    LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
    LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);
    LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
    //设置串口外设-------------------------------------------------------------
    USART_InitStruct.BaudRate = baud_rate;                                                                  //设置波特率
    USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;                                                     //8bit数据位
    USART_InitStruct.StopBits = LL_USART_STOPBITS_1;                                                        //1bit停止位
    USART_InitStruct.Parity = LL_USART_PARITY_NONE;                                                         //无奇偶校验
    USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;                                          //启用TXRX
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;                                         //不使用流控
    USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;                                               //串口16倍过采样
    LL_USART_Init(USART2, &USART_InitStruct);                                                               //串口初始化
    LL_USART_DisableOverrunDetect(USART2);                                                                  // 禁用过载检测
    LL_USART_DisableDMADeactOnRxErr(USART2);                                                                // 不使用接收错误关闭DMA
    LL_USART_ConfigAsyncMode(USART2);                                                                       //使用异步模式
    LL_USART_EnableDMAReq_TX(USART2);                                                                       //使能UART DMA TX
    LL_USART_EnableDMAReq_RX(USART2);                                                                       //使能UART DMA RX
    NVIC_SetPriority(USART2_IRQn, 0);                                                                       //设置uart2中断服务优先级
    NVIC_EnableIRQ(USART2_IRQn);                                                                            //使能uart2中断服务
    LL_USART_Enable(USART2);                                                                                //串口启动运行
    //触发串口接收--------------------------------------------------------------
    uart2_rx_busy_flag = 0;                                                                                 // 读缓冲区忙碌标志位清零
    MSP_Uart2_Read(NULL);                                                                                   // 首次启动串口接收（防止溢出）
}
#else
/**
 * @brief 初始化串口2，不使用DMA
 * 
 * @param baud_rate 
 */
void MSP_Usart2_Init(uint32_t baud_rate)
{
    LL_USART_InitTypeDef USART_InitStruct = {0};
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    //外设时钟---------------------------------------------------------------
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    //设置gpio---------------------------------------------------------------
    // PA2   ------> USART2_TX
    // PA3   ------> USART2_RX
    GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
    // GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
    // LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    //设置串口外设-------------------------------------------------------------
    USART_InitStruct.BaudRate = baud_rate;                                                          //设置波特率
    USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;                                             //8bit数据位
    USART_InitStruct.StopBits = LL_USART_STOPBITS_1;                                                //1bit停止位
    USART_InitStruct.Parity = LL_USART_PARITY_NONE;                                                 //无奇偶校验
    USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;                                  //启用TXRX
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;                                 //不使用流控
    USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;                                       //串口16倍过采样
    LL_USART_Init(USART2, &USART_InitStruct);                                                       //串口初始化
    LL_USART_Init(USART2, &USART_InitStruct);
    LL_USART_ConfigAsyncMode(USART2);
    LL_USART_Enable(USART2);
}
#endif

/**
 * @brief
 *
 * @param baud_rate
 */
void MSP_Usart4_Init(uint32_t baud_rate)
{
    // LL_USART_InitTypeDef USART_InitStruct = {0};
    // LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    // //外设时钟---------------------------------------------------------------
    // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART4);
    // LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    // LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
    // //设置gpio---------------------------------------------------------------
    // // PA0   ------> USART4_TX
    // // PA1   ------> USART4_RX
    // GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
    // GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    // GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    // GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    // GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    // GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
    // LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
    // GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    // GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    // GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    // GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    // GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
    // LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // // 使能DMA中断
    // NVIC_SetPriority(DMA1_Ch4_7_DMAMUX1_OVR_IRQn, 3);
    // NVIC_EnableIRQ(DMA1_Ch4_7_DMAMUX1_OVR_IRQn);
    // //设置接收DMA-------------------------------------------------------------
    // LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_5, LL_DMAMUX_REQ_USART4_RX);                               // 设置DMA1通道3的外设请求源为USART2的接收请求
    // LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_5, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);             // 设置DMA1通道3的数据传输方向为从外设到内存
    // LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PRIORITY_HIGH);                           // 设置DMA1通道3的优先级为中
    // LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MODE_NORMAL);                                             // 设置DMA1通道3的模式为正常模式
    // LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PERIPH_NOINCREMENT);                             // 设置DMA1通道3的外设地址不增量
    // LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MEMORY_INCREMENT);                               // 设置DMA1通道3的内存地址增量模式
    // LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PDATAALIGN_BYTE);                                   // 设置DMA1通道3的外设数据宽度为8位
    // LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MDATAALIGN_BYTE);                                   // 设置DMA1通道3的内存数据宽度为8位
    // //设置发送DMA-------------------------------------------------------------
    // LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_6, LL_DMAMUX_REQ_USART4_TX);
    // LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_6, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
    // LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PRIORITY_HIGH);
    // LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MODE_NORMAL);
    // LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PERIPH_NOINCREMENT);
    // LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MEMORY_INCREMENT);
    // LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_6, LL_DMA_PDATAALIGN_BYTE);
    // LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_6, LL_DMA_MDATAALIGN_BYTE);
    // //设置串口外设-------------------------------------------------------------
    // USART_InitStruct.BaudRate = baud_rate;                                                                  //设置波特率
    // USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;                                                     //8bit数据位
    // USART_InitStruct.StopBits = LL_USART_STOPBITS_1;                                                        //1bit停止位
    // USART_InitStruct.Parity = LL_USART_PARITY_NONE;                                                         //无奇偶校验
    // USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;                                          //启用TXRX
    // USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;                                         //不使用流控
    // USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;                                               //串口16倍过采样
    // LL_USART_Init(USART4, &USART_InitStruct);                                                               //串口初始化
    // LL_USART_Disable(USART4);                                                                               // 关使能，使下一行生效
    // LL_USART_SetTXRXSwap(USART4, LL_USART_TXRX_SWAPPED);                                                    // 交换TX/RX引脚 This bitfield can only be written when the USART is disabled (UE = 0).
    // LL_USART_DisableOverrunDetect(USART4);                                                                  // 禁用过载检测（没有及时读走数据报错）
    // LL_USART_DisableDMADeactOnRxErr(USART4);                                                                //不使用接收错误关闭DMA
    // LL_USART_ConfigAsyncMode(USART4);                                                                       //使用异步模式
    // LL_USART_EnableDMAReq_TX(USART4);                                                                       //使能UART DMA TX
    // LL_USART_EnableDMAReq_RX(USART4);                                                                       //使能UART DMA RX
    // NVIC_SetPriority(USART3_4_IRQn, 0);                                                                     //设置uart2中断服务优先级
    // NVIC_EnableIRQ(USART3_4_IRQn);                                                                          //使能uart2中断服务
    // LL_USART_Enable(USART4);                                                                                //串口启动运行
    // //触发串口接收--------------------------------------------------------------
    // uart4_rx_busy_flag = 0;                                                                                 // 读缓冲区忙碌标志位清零
    // MSP_Uart4_Read(NULL);                                                                                   // 首次启动串口接收（防止溢出）
}

/**
 * @brief 设置指定串口的DMA发送
 *
 * @param USARTx
 * @param Stream
 */
void USARTx_DMA_TransferSetting(USART_TypeDef *USARTx, uint32_t Stream)
{
    // LL_DMA_SetMemoryAddress(DMA1, Stream, (uint32_t)uart4_tx_buffer_dma);    // 设置发送缓冲区
    // LL_DMA_SetPeriphAddress(DMA1, Stream, (uint32_t)(&USARTx->RDR));
    // LL_DMA_SetDataLength(DMA1, Stream, 1);
    // LL_DMA_EnableIT_TC(DMA1, Stream);                             // 设置传输完成中断
    // LL_DMA_EnableStream(DMA1, Stream);
    // LL_USART_EnableDMAReq_TX(USARTx);
}

/**
 * @brief 关闭指定串口的DMA传输
 *
 * @param USARTx
 * @param Stream
 */
void USARTx_DMA_TransferDisbale(USART_TypeDef *USARTx, uint32_t Stream)
{
    // LL_DMA_DisableIT_TC(DMA1, Stream);        // 关闭传输完成中断
    // LL_DMA_DisableStream(DMA1, Stream);       // 关闭流
    // LL_USART_EnableDMAReq_TX(USARTx);         // 关闭DMA发送传输
}

#if UART2_USE_DMA
//uart2 DMA发送数据
uint8_t Msp_Uart2_Write(uint8_t *pdata, uint16_t len)
{
    //忙碌/错误检查
    if(uart2_tx_busy_flag)                                                          //如果写缓冲区忙
        return MSP_UART_FAILURE;                                                    //返回失败
    if(len > UART2_TX_BUFFER_SIZE)                                                  //如果需要写的字节数大于发送缓冲区
        return MSP_UART_FAILURE;                                                    //返回失败
    //发送数据
    uart2_tx_busy_flag = 1;                                                         //设置发送忙碌标志位
    // uart2_tx_data_len = len;                                                        //记录需要发送的数据量
    memcpy(uart2_tx_buffer, pdata, len);                                            //拷贝数据到发送缓冲区
    Msp_Uart2_Write_Dma(len);                                                       //设置uart2发送DMA，数据开始发送
    return MSP_UART_SUCCESS;                                                        //返回成功
}

//设置uart2发送DMA
static void Msp_Uart2_Write_Dma(uint16_t len)
{
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4,\
        LL_USART_DMA_GetRegAddr(USART2, LL_USART_DMA_REG_DATA_TRANSMIT));           //设置外设寄存器地址
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t)uart2_tx_buffer);     //设置发送缓冲区地址
    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, len);                              //设置发送数据量
    LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_4);                                     //使能发送完成中断
    LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_4);                                     //使能发送失败中断
    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);                                   //通道使能，传输开始
}

//uart2发送中断回调函数
void Msp_Uart2_Write_Dma_Callback(void)
{
    //如果发生了DMA传输完成中断或传输错误中断
    if(LL_DMA_IsActiveFlag_TC4(DMA1) || LL_DMA_IsActiveFlag_TE4(DMA1))
    {
        LL_DMA_ClearFlag_GI4(DMA1);//清除所有的中断
        LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);//关闭DMA传输通道
        uart2_tx_busy_flag = 0;//清除写串口忙碌标志位
    }
}

/**
 * @brief uart2接收数据
 *
 * @param pdata
 * @return uint16_t
 */
uint16_t MSP_Uart2_Read(uint8_t *pdata)
{
    // 忙碌检查
    if (uart2_rx_busy_flag)                             // 串口接收当前正在接收数据
        return 0;                                       // 返回0，表示没有数据被拷贝
    /* 搬运上次读取的数据 */
    memcpy(pdata, uart2_rx_buffer, uart2_rx_data_len);  // 拷贝接收数据到指定内存
    uint16_t read_len = uart2_rx_data_len;              // 记录拷贝的数据量
    uart2_rx_data_len = 0;                              // 清空接收计数
    /* 准备接收下次数据 */
    uart2_rx_busy_flag = 1;                             // 置位串口接收忙碌标志位
    MSP_Uart2_Read_Dma(UART2_RX_BUFFER_SIZE);           // 重启串口DMA接收
    LL_USART_ClearFlag_IDLE(USART2);                    // 清除接收空闲中断标志位
    LL_USART_EnableIT_IDLE(USART2);                     // 使能接收空闲中断
    return read_len;                                    // 返回读取的串口接收数据量
}

// 设置uart2 通道3 接收DMA
static void MSP_Uart2_Read_Dma(uint16_t len)
{
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_3, (uint32_t)(&USART2->RDR));      // 设置外设寄存器地址
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_3, (uint32_t)uart2_rx_buffer);     // 设置接收缓冲区地址
    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, len);                              // 设置接收数据量
    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);                                   // 通道使能，传输开始
}

/**
 * @brief uart2接收中断回调函数
 *
 */
// uart2接收中断回调函数
void MSP_Uart2_Read_Uart_Callback(void)
{
    if(LL_USART_IsActiveFlag_IDLE(USART2))                                          // 检查空闲标志
    {
        LL_USART_DisableIT_IDLE(USART2);                                            // 停止空闲中断
        LL_USART_ClearFlag_IDLE(USART2);                                            // 清除中断标志位
        uint8_t delay = 255; while(delay--);                                        // 简单延时，保证DMA完全搬运数据
        LL_DMA_ClearFlag_TC3(DMA1);
        LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_3);                              // 停止串口DMA传输通道
        uart2_rx_data_len = UART2_RX_BUFFER_SIZE - \
            LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_3);                           // 记录当前接收的数据量
        uart2_rx_busy_flag = 0;                                                     // 复位串口接收忙碌标志位
    }
    if(LL_DMA_IsActiveFlag_TC3(DMA1))
    {
        LL_DMA_ClearFlag_TC3(DMA1);
        _DEBUG_PRINT(DBG_ERR , "DMA data transfer recv!\r\n");
    }
    else if(LL_DMA_IsActiveFlag_TE3(DMA1))
    {
        LL_DMA_ClearFlag_GI3(DMA1);
        _DEBUG_PRINT(DBG_ERR , "DMA data transfer failed!\r\n");
    }
}
#endif
